Requisitos

Este notebook es un R Markdown que fue desarrollado en RStudio para ser ejecutado con código en Python3. Por lo tanto, además de tener instalado Python3, se debe instalar desde la consola de RStudio o en la terminal ejecutando R la biblioteca Reticulate para ligar Python con R, mediante el comando:

install.packages("reticulate")

Además, se requiere instalar las siguientes bibliotecas desde Python3 con los comandos respectivos desde la terminal.

-Pandas

pip3 install pandas

-Numpy

pip3 install numpy

-Matplotlib

pip3 install matplotlib

-Scikit Learn

pip3 install scikit-learn

-Tensorflow

En la terminal se instala la dependencia Testtresources:

sudo apt install python3-testresources

Luego, se instala Tensorflow con el siguiente comando:

pip3 install tensorflow

Introducción

Conceptos Claves

Machine Learning

El aprendizaje automático o machine learning, es un subcampo de las ciencias de la computación que busca que las computadoras puedan aprender, es decir, que puedan mejorar los resultados obtenidos a partir de la experiencia.

¿ Qué es “aprender” para una máquina?

Una máquina utiliza un modelo matemático para relizar sus funciones. Estos modelos contienen parámetros, y la intención del aprendizaje de máquina es encontrar los parámetros que le permitan tener la mejor respuesta ante una entrada de información. Es a través de la modificación de estos parámetros, que una computadora puede “aprender”, es decir que puede obtener un mejor resultado, mejorando ella misma su rendimiento previo.

Imagen de: https://commons.wikimedia.org/wiki/File:Slope.gif

¿Cómo aprende una máquina?

La forma en la que una máquina aprende varía dependiendo del modelo o arquitectura de aprendizaje de máquina que se esté utilizando. Pero de forma general, lo que se busca es calcular el error de la salida generada por la máquina con respecto a la salida deseada. Este error va a estar en función de los parámetros del modelo, es decir que lo que se busca es obtener cómo varía el error al variar los parámetros. Una vez que se obtiene una función que describa el error, se bucará encontrar el valor de los parámetros que disminuyan el error. Encontrar el menor error es equivalente a encontrar un mínimo de la función, lo cuál puede conseguirse derivando la función, o como es el caso de las redes neuronales, que poseen muchos parámetros, calculando el gradiente.

Imagen de: https://towardsdatascience.com/a-visual-explanation-of-gradient-descent-methods-momentum-adagrad-rmsprop-adam-f898b102325c

Entonces básicamente para que la máquina aprenda se requieren dos pasos: - Calcular el error - Optimizar el error (encontrar el mínimo)

Para estos dos pasos existen diversos métodos:

Cálculo del error:
  • Raíz cuadrada media
  • Error absoluto medio
  • Error absoluto medio escalado
  • Entropía cruzada categórica
  • Entropía cruzada binaria

Optimización del error

  • Descenso estocástico del gradiente – SGD
  • Adam
  • Adagrad
  • Adadelta

- Redes Neuronales

Las redes neuronales son un tipo de aprendizaje automático, que se basa en el uso de unidades de cálculo llamadas neuronas. Una red neuronal, como su nombre lo indica, está formada por un conjuto de estas neuronas conectadas.

Una red neuronal se compone de forma general por una capa de entrada, una o más capas de neuronas (también llamadas capas ocultas), y una capa de salida

Estructura de red neuronal, una capa

Imagen de: https://commons.wikimedia.org/wiki/File:Colored_neural_network.svg

Estructura de red neuronal, dos capas

Imagen de: https://commons.wikimedia.org/wiki/File:Neural_network_bottleneck_achitecture.svg

La Neurona

Una neurona es una unidad que se encarga de realizar una suma ponderada de las entradas que llegan a esa neurona

Imagen de: https://commons.wikimedia.org/wiki/File:

Es decir que la salida está dada por

lo que se puede reescribir como

La Función de Activación

Para evitar la linealidad de las salidas de una neurona se utiliza una función de activación. Existen varias funciones de activación, pero por lo general son funciones acotadas. Entre las funciones de activación más usadas están:

Imagen de: https://commons.wikimedia.org/wiki/File:Hyperbolic_Tangent.svg

  • Sigmoide

Imagen de: https://commons.wikimedia.org/wiki/File:Sigmoid-function-2.svg

La función de activación se aplica justo antes de la salida

Imagen de: https://commons.wikimedia.org/wiki/File:Perceptr%C3%B3n_5_unidades.svg

- Recurrent Neural Network (RNN)

- Long Short-Term Memory (LSTM)

- RNN vs LSTM

Diagrama

Bibliotecas Implementadas

- TensorFlow

- Keras

Keras es una API (Application Programming Interface) especializada para trabajar con redes neuronales. Keras corre sobre Tensorflow, es decir que utiliza las funciones que tensorflow provee y le agrega una capa más de abstracción, simplificando algunoas de los procesos más comunes y permitiendo que el usuario no tenga que preocuparse por algunos detalles, facilitando así la creación de redes neuronales, en especial para personas principiantes. Si se requiere un manejo más minuscioso de algunas funciones de la red neuronal, será necesario descender hasta el propio tensorflow.

Implementación en Python

A continuación se implementa el análisis de los datos en Python mediante la utilización de distintas bibliotecas. Se procede a mostrar el código fuente, así como la salida obtenida de este con una detallada descripción del mismo.

1. Importar las bibliotecas a utilizar.

import pandas as pd

import numpy as np

import math

import matplotlib.pyplot as plt

from sklearn.preprocessing import MinMaxScaler

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, LSTM

2. Funciones.

a. Cargar datos csv:

Se carga el archivo csv en la variable. Retorna el data frame con las columnas de interés.

def CargarArchivo(file, online=False):
    if online:
    # Se carga el archivo online
        datos = pd.read_csv(file)
    else:
    # Se carga el archivo local
        datos = pd.read_csv('../Datos/' + file)
    
    #Se convierte en data frame con pandas 
    datos_pd = pd.DataFrame(datos)
    # Se eliminan las columnas con los nombres "Province/State", "Lat" y "Long"
    datos_pd_reducidos = datos_pd.drop(['Province/State', 'Lat', 'Long'], axis=1)
    # Retorna datos con las 3 columnas eliminadas
    return datos_pd_reducidos

b. Seleccionar los datos de interés Acumulados:

Se seleccionan los paises de interés para el análisis, con los casos acumulados.

def SeleccionarPaisesAcumulados(datos, paises=''):
    #Se establece la columna 'Country/Region' como índice
    datos = datos.set_index('Country/Region')
    #Se elige solo la info de los países de la lista
    if paises != '':
        datos_paises = datos.loc[paises]
        #Retorna datos solo de los países
        return datos_paises
    #Retorna datos solo de los países
    else:
        return datos

c. Generar los datos y gráficos de los datos obtenidos ACUMULADOS:

Se genera una función general para analizar los datos acumulados que se tienen para hacer las predicciones.

def Analice_archivoAcumulados(archivo, paises):
    datos_reducidos = CargarArchivo(archivo, online =True)
    datos_paises = SeleccionarPaisesAcumulados(datos_reducidos, paises)
    #e. Se crea una lista con elementos desde 0 hasta el número de fechas menos 1
    n_fechas = datos_paises.shape[1]
    x_eje = list(range(0, n_fechas))
    
    #f. Se grafican los datos
    #--Se define los posibles títulos para el gráfico
    titulo_grafico = ''
    if archivo=='time_series_covid19_confirmed_global.csv' or archivo[-40:]=='time_series_covid19_confirmed_global.csv':
        titulo_grafico = 'Casos Confirmados Acumulados de Covid-19'
    elif archivo=='time_series_covid19_deaths_global.csv' or archivo[-37:]=='time_series_covid19_deaths_global.csv':
        titulo_grafico = 'Casos de Muerte Acumulados por Covid-19'
    elif archivo=='time_series_covid19_recovered_global.csv' or archivo[-40:]=='time_series_covid19_recovered_global.csv':
        titulo_grafico = 'Casos Recuperados Acumulados de Covid-19'
    
    #--Impresiones en Consola
    #Columnas Eliminadas
    print("-----------------> ANÁLISIS DE DATOS: "+titulo_grafico)
    #Países de Interés
    print("\n--> Países seleccionados: "+str(paises))
    print(datos_paises)    
        
    #--For para graficar cada país
    for i in range(len(paises)):
        plt.plot(x_eje, datos_paises.loc[paises[i]],label=paises[i])
    #--Títulos del gráfico
    plt.title(titulo_grafico)
    plt.xlabel('Días desde el '+datos_paises.columns[0]+' hasta el '+datos_paises.columns[n_fechas-1]+'  [mes/día/año]')
    plt.ylabel('Casos reportados')
    plt.legend()
    plt.show()
    plt.close()
    print("<----------------- FINALIZA ANÁLISIS DE DATOS <-----------------")

d. Generar los datos y gráficos de los datos obtenidos Diarios:

Se seleccionan los paises de interés para el análisis, con los casos diarios.

def SeleccionarPaisesDiarios(datos, paises=''):
    #Se establece la columna 'Country/Region' como índice
    datos = datos.set_index('Country/Region')
    #Se elige solo la info de los países de la lista
    if paises != '':
        datos_paises = datos.loc[paises]
        #Se calculan los casos diarios apartir de una resta de los acumulados
        datos_paises = datos_paises.diff(axis=1).fillna(datos_paises.iloc[0,0]).astype(np.int64)
        #Retorna datos solo de los países
        return datos_paises
    #Retorna datos solo de los países
    else:
        #Se calculan los casos diarios apartir de una resta de los acumulados
        datos = datos.diff(axis=1).fillna(datos.iloc[0,0]).astype(np.int64)
        return datos

e. Generar los datos y gráficos de los datos obtenidos DIARIOS:

Se genera una función general para analizar los datos diarios que se tienen para hacer las predicciones.

def Analice_archivoDiarios(archivo, paises):
    datos_reducidos = CargarArchivo(archivo, online =True)
    datos_paises = SeleccionarPaisesDiarios(datos_reducidos, paises)
    #e. Se crea una lista con elementos desde 0 hasta el número de fechas menos 1
    n_fechas = datos_paises.shape[1]
    x_eje = list(range(0, n_fechas))
    
    #f. Se grafican los datos
    #--Se define los posibles títulos para el gráfico
    titulo_grafico = ''
    if archivo=='time_series_covid19_confirmed_global.csv' or archivo[-40:]=='time_series_covid19_confirmed_global.csv':
        titulo_grafico = 'Casos Confirmados Diarios de Covid-19'
    elif archivo=='time_series_covid19_deaths_global.csv' or archivo[-37:]=='time_series_covid19_deaths_global.csv':
        titulo_grafico = 'Casos de Muerte Diarios por Covid-19'
    elif archivo=='time_series_covid19_recovered_global.csv' or archivo[-40:]=='time_series_covid19_recovered_global.csv':
        titulo_grafico = 'Casos Recuperados Diarios de Covid-19'
    
    #--Impresiones en Consola
    #Columnas Eliminadas
    print("-----------------> ANÁLISIS DE DATOS: "+titulo_grafico)
    #Países de Interés
    print("\n--> Países seleccionados: "+str(paises))
    print(datos_paises)    
        
    #--For para graficar cada país
    for i in range(len(paises)):
        plt.plot(x_eje, datos_paises.loc[paises[i]],label=paises[i])
    #--Títulos del gráfico
    plt.title(titulo_grafico)
    plt.xlabel('Días desde el '+datos_paises.columns[0]+' hasta el '+datos_paises.columns[n_fechas-1]+'  [mes/día/año]')
    plt.ylabel('Casos reportados')
    plt.legend()
    plt.show()
    plt.close()
    print("<----------------- FINALIZA ANÁLISIS DE DATOS <-----------------")

f. Division los datos para obtener más muestras:

Se genera una función que divide los datos, con el fin de poder ingresar más muestras al entrenamiento del modelo

Imagen de: https://stackoverflow.com/questions/31947183/how-to-implement-walk-forward-testing-in-sklearn

def walk_forward_format_2(train_data, in_size, out_size, step=1):
    # Aplanamiento de datos
    data = train_data.reshape(-1,1,1)
    # Cantidad de muestras
    samples = math.floor((data.shape[0]-(in_size+out_size))/step)
    if (samples<1):
        raise NameError("El tamaño de las entradas más las salidas es mayor al tamaño de los datos")
    # Tamaño de los datos de validación
    validation_size = out_size
    # Tamaño de los datos de entrada
    input_size = in_size
    # Arreglo de entrada con muestras walk-forward
    wf_data_in = []
    # Arreglo de validacion con datos walk-forward
    wf_data_val = []
    # Se divide en cada una de las muestras
    for i in range(0,samples):
        wf_data_in.append(data[i*step:i*step+input_size])
        wf_data_val.append(data[i*step+input_size:i*step+input_size+validation_size])
    # Se convierten a  np arrays con la forma deseada
    wf_data_in_np = np.array(wf_data_in).reshape(samples,-1)
    wf_data_val_np = np.array(wf_data_val).reshape(samples,-1)
    return wf_data_in_np, wf_data_val_np

g. Division de los datos cuando se tienen varios paises:

Se genera una función que divide los datos para obtener más muestras, cuando se tiene más de un país en el dataframe

def multi_walk_forward_format(train_data, in_size, out_size, step=1):
    # Se inicializan listas vacías donde se colocarán las muestras
    x_res = []
    y_res = []
    # Se hace un loop para recorrer cada país
    for i in train_data:
        # Se aplana el dato
        data_temp = i.reshape(1,-1)
        # Se llama a la función que divide los datos para un solo país
        x_temp,y_temp = walk_forward_format_2(data_temp,in_size, out_size, step)
        # Cada muestra obtenida para el país dse guarda en la lista con todas las muestras de todos los paises
        # Esto se hace parta los datos de entrada
        for j in x_temp:
            x_res.append(j)
            # Y para los de salida
        for j in y_temp:
            y_res.append(j)
        # Finalmente se convierten las listas a arreglos de numpay y se les da la forma deseada
        x_np = np.array(x_res).reshape(-1,in_size)
        y_np = np.array(y_res).reshape(-1,out_size)
    return x_np,y_np

3. Se imprime en consola la información para los casos confirmados, de muerte y recuperados, tanto acumulados como diarios.

# Main Parte 3: Se visualizan los datos

# Datos locales de respaldo
file1 = 'time_series_covid19_confirmed_global.csv' 
file2 = 'time_series_covid19_deaths_global.csv'
file3 = 'time_series_covid19_recovered_global.csv'

# URL con los datos
url1 = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv'
url2 = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv'
url3 = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_recovered_global.csv'

paises = ['Costa Rica']

Archivo 1 (Casos Confirmados): “time_series_covid19_confirmed_global.csv”

Analice_archivoAcumulados(url1, paises)
## -----------------> ANÁLISIS DE DATOS: Casos Confirmados Acumulados de Covid-19
## 
## --> Países seleccionados: ['Costa Rica']
##                 1/22/20  1/23/20  1/24/20  ...  2/21/21  2/22/21  2/23/21
## Country/Region                             ...                           
## Costa Rica            0        0        0  ...   201678   202674   203097
## 
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------

Analice_archivoDiarios(url1,paises)
## -----------------> ANÁLISIS DE DATOS: Casos Confirmados Diarios de Covid-19
## 
## --> Países seleccionados: ['Costa Rica']
##                 1/22/20  1/23/20  1/24/20  ...  2/21/21  2/22/21  2/23/21
## Country/Region                             ...                           
## Costa Rica            0        0        0  ...        0      996      423
## 
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------

Archivo 2 (Casos de Muerte): “time_series_covid19_deaths_global.csv”

Analice_archivoAcumulados(url2, paises)
## -----------------> ANÁLISIS DE DATOS: Casos de Muerte Acumulados por Covid-19
## 
## --> Países seleccionados: ['Costa Rica']
##                 1/22/20  1/23/20  1/24/20  ...  2/21/21  2/22/21  2/23/21
## Country/Region                             ...                           
## Costa Rica            0        0        0  ...     2763     2782     2785
## 
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------

Analice_archivoDiarios(url2,paises)
## -----------------> ANÁLISIS DE DATOS: Casos de Muerte Diarios por Covid-19
## 
## --> Países seleccionados: ['Costa Rica']
##                 1/22/20  1/23/20  1/24/20  ...  2/21/21  2/22/21  2/23/21
## Country/Region                             ...                           
## Costa Rica            0        0        0  ...        0       19        3
## 
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------

Archivo 3 (Casos Recuperados): “time_series_covid19_recovered_global.csv”

Analice_archivoAcumulados(url3, paises)
## -----------------> ANÁLISIS DE DATOS: Casos Recuperados Acumulados de Covid-19
## 
## --> Países seleccionados: ['Costa Rica']
##                 1/22/20  1/23/20  1/24/20  ...  2/21/21  2/22/21  2/23/21
## Country/Region                             ...                           
## Costa Rica            0        0        0  ...   169053   172280   173591
## 
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------

Analice_archivoDiarios(url3,paises)
## -----------------> ANÁLISIS DE DATOS: Casos Recuperados Diarios de Covid-19
## 
## --> Países seleccionados: ['Costa Rica']
##                 1/22/20  1/23/20  1/24/20  ...  2/21/21  2/22/21  2/23/21
## Country/Region                             ...                           
## Costa Rica            0        0        0  ...        0     3227     1311
## 
## [1 rows x 399 columns]
## <----------------- FINALIZA ANÁLISIS DE DATOS <-----------------

4. Análisis con Redes Neuronales.

En esta sección se procede a implementar una Red Neuronal. Primero se seleccionan los datos para entrenar a la red neuronal, por lo tanto del total de días se seleccionan una gran parte para entrenar la red y con esto se proyecta para una cantidad de días el comportamiento de los casos por Covid-19, para posteriormente comparar este pronóstico con los datos reales.

4.1 Selecionar datos para entrenar y datos de prueba

# Se escoge cúales datos se utilizarán (Acumulados, defunciones o recuperados)
url = url1
#url = url2
#url = url3

# Se cargan los datos a un dataframe
datos_totales = CargarArchivo(url,online=True)
# Se imprimen los datos para observarlos
print(datos_totales)
##          Country/Region  1/22/20  1/23/20  ...  2/21/21  2/22/21  2/23/21
## 0           Afghanistan        0        0  ...    55604    55617    55646
## 1               Albania        0        0  ...   100246   101285   102306
## 2               Algeria        0        0  ...   111917   112094   112279
## 3               Andorra        0        0  ...    10699    10712    10739
## 4                Angola        0        0  ...    20519    20548    20584
## ..                  ...      ...      ...  ...      ...      ...      ...
## 269             Vietnam        0        2  ...     2383     2392     2403
## 270  West Bank and Gaza        0        0  ...   173635   174969   176377
## 271               Yemen        0        0  ...     2165     2176     2187
## 272              Zambia        0        0  ...    74503    75027    75582
## 273            Zimbabwe        0        0  ...    35796    35862    35910
## 
## [274 rows x 400 columns]

Se comprueba que no hayan campos vacíos en el dataframe

print(datos_totales.isnull().values.any())
## False
# Días a excluir de los datos reales
dias_pronostico = 30
# Días que se ingresarán como entrada a la red
dias_disponibles = 320
#paises = ['Costa Rica','Guatemala', 'El Salvador', "Panama", 'Honduras']
paises = ['Costa Rica']

#datos_pais = SeleccionarPaisesAcumulados(CargarArchivo(url,online=True), paises)
datos_pais = SeleccionarPaisesDiarios(CargarArchivo(url,online=True), paises)
datos_pais
##                 1/22/20  1/23/20  1/24/20  ...  2/21/21  2/22/21  2/23/21
## Country/Region                             ...                           
## Costa Rica            0        0        0  ...        0      996      423
## 
## [1 rows x 399 columns]

Se seleccionan los datos para el entrenamiento

train_data = datos_pais.iloc[:,:-dias_pronostico].to_numpy()

print(train_data.shape)
## (1, 369)

Al trabajar con series de tiempo se puede ampliar la cantidad de muestras si los datos disponibles se dividen utilizando un método llamado ‘walk-forward’ o ‘roll-forward’. Este método consiste en tomar una muestra o ventana de datos, e irlos desplazado una cierta cantidad de pasos. De esta forma se pueden obtener una mayor cantidad de muestras.

train_x,train_y = multi_walk_forward_format(train_data,dias_disponibles,dias_pronostico,10)

print(train_x.shape)
## (1, 320)

4.2 Escalar los datos seleccionados

Una forma recomendada de optimizar el proceso de entrenamiento es utilizar datos que estén entre un margen de 0 a 1, es por ello que los casos se escalan dentro de este margen.

# Se establece que la escala se hará utilizando los datos de entreno para los máximos y mínimos,
#es decir, al valor mínimo en datos_entreno se asigna como 0, y el máximo valor de datos_entreno se asigna como 1

sc_in = MinMaxScaler(feature_range=(0,1))
sc_out = MinMaxScaler(feature_range=(0,1))

# Se hace el ajuste de los datos, tanto para los datos de entrada com para los de salida, cada uno por aparte
sc_in.fit(train_x)
## MinMaxScaler()
sc_out.fit(train_y)

# Se escalan los datos de entrada y salida del entreno
## MinMaxScaler()
train_x_s = sc_in.transform(train_x)
train_y_s = sc_out.transform(train_y)

Una vez escalados los datos es necesario cambiar la forma como están acomodados los datos. Esto se hace únicamente porque así es la forma en la que la función de Keras que realiza el modelo recibe los datos.

Esta forma es de la siguiente manera:

(Cantidad de muestras, cantidad de pasos de tiempo, cantidad de características)

train_x_r = train_x_s.reshape(train_x_s.shape[0],train_x_s.shape[1],1)
train_y_r = train_y_s.reshape(train_y_s.shape[0],train_y_s.shape[1],1)

4.3 Definir los parámetros del Modelo LSTM

Ahora se definen los parámetros del modelo LSTM a crear.

verbose, epochs, batch_size = 1, 1, 1
n_timesteps, n_features, n_outputs = train_x_r.shape[1], train_x_r.shape[2], train_y_r.shape[1]

4.4 Creación del modelo LSTM

Modelo A:

Modelo A, se ajustó mejor la predicción. Es el que se implementa en este proyecto.

#Inicialización del modelo
model = Sequential()

#Se agrega una capa interna LSTM 
model.add(LSTM(30, return_sequences=False, activation='relu', input_shape=(n_timesteps, n_features)))
model.add(Dropout(0.2))

#Se agrega la capa externa de salida
model.add(Dense(n_outputs, activation='relu'))
Modelo B:

EJEMPLO. Es posible agregar más capas internas LSTM pero incrementa el tiempo de entrenamiento, aunque puede o no mejorar la aproximación. Además, entre más capas internas en la red, nos adentramos en el campo del Deep Learning. El Modelo B no fue implementado ya que las predicciones se ajustaban más con solo una capa LSTM (Modelo A).

#Inicialización del modelo
model_B = Sequential()

#-Capa 1 LSTM: Se agrega una capa interna LSTM, se debe especificar el input_shape solo en la primera
model_B.add(LSTM(30, return_sequences=True, activation='relu', input_shape=(n_timesteps, n_features)))
model_B.add(Dropout(0.2))

#-Capa 2 LSTM
model_B.add(LSTM(50, return_sequences=True, activation='relu'))
model_B.add(Dropout(0.2))

#-Capa 3 LSTM
model_B.add(LSTM(50, activation='relu'))
model_B.add(Dropout(0.2))

#Se agrega la capa externa de salida
model_B.add(Dense(n_outputs, activation='relu'))

4.5 Compilar/optimizar modelo LSTM

# Se establecen el método para obtener el error y para minimizarlo
model.compile(loss='mse', optimizer='adam')

# Se entrena el modelo con los datos de entreno
model.fit(train_x_r, train_y_r, epochs=epochs, batch_size=batch_size, verbose=verbose)

#Se despliega el modelo implementado, Modelo A
## 
## 1/1 [==============================] - ETA: 0s - loss: 0.0000e+00
## 1/1 [==============================] - 3s 3s/step - loss: 0.0000e+00
## <tensorflow.python.keras.callbacks.History object at 0x000000006AD1B4C0>
model.summary()
## Model: "sequential"
## _________________________________________________________________
## Layer (type)                 Output Shape              Param #   
## =================================================================
## lstm (LSTM)                  (None, 30)                3840      
## _________________________________________________________________
## dropout (Dropout)            (None, 30)                0         
## _________________________________________________________________
## dense (Dense)                (None, 30)                930       
## =================================================================
## Total params: 4,770
## Trainable params: 4,770
## Non-trainable params: 0
## _________________________________________________________________

4.6 Datos para el test

Ahora se procede a seleccionar los datos de entrada para la prueba.

pais = ['Costa Rica']
#datos_pais_test = SeleccionarPaisesAcumulados(CargarArchivo(url,online=True), pais)
datos_pais_test = SeleccionarPaisesDiarios(CargarArchivo(url,online=True), paises)
# Se seleccionan los últimos datos disponibles menos los que se usaran para comprobar si la predicción es correcta
test_x   = datos_pais_test.iloc[:,-(dias_pronostico+dias_disponibles):-dias_pronostico].to_numpy()
# Se escalan los datos de entrada
test_x_s = sc_in.transform(test_x)
# Se acomodan en la forma que el modelo de Keras los recibe
test_x_r = test_x.reshape(test_x_s.shape[0],test_x_s.shape[1],1)

Grafica de Datos Reales utilizados para entrenar el Modelo LSTM

for i in test_x:
  plt.plot(i)

4.7 Predicción de datos y tratamiento de los datos obtenidos

# Se realiza la predicción del modelo
prediction = model.predict(test_x_r)

print(prediction.shape)
## (1, 30)
print(prediction)
## [[1681.6934  1387.0125     0.         0.         0.       143.73145
##   1100.3698     0.         0.         0.         0.       514.2669
##    136.36772    0.      1042.8093   165.33388    0.         0.
##   1102.1138   283.71545  317.3093     0.         0.      1307.3981
##      7.85791  625.57605    0.         0.         0.       378.21414]]
# El resultado está escalado, por lo que es necesario invertir el escalamiento para obtener los valores en la escala correcta
prediction_rescaled = sc_out.inverse_transform(prediction)
print(prediction_rescaled)
## [[4417.6934  2396.0125  1258.      1127.      1132.       143.73145
##   1100.3698  2222.       927.      1167.      1125.      1598.2668
##    136.36772    0.      3463.8093  1076.3339  1138.      1048.
##   1102.1138   283.71545  317.3093  2772.      1037.      2622.398
##   1214.8579   625.57605    0.         0.      3115.      1533.2141 ]]
# Se obtienen los datos reales que se querían predecir, para poder comparar
test_y = datos_pais.iloc[:,-dias_pronostico:].to_numpy()

print(prediction)
## [[1681.6934  1387.0125     0.         0.         0.       143.73145
##   1100.3698     0.         0.         0.         0.       514.2669
##    136.36772    0.      1042.8093   165.33388    0.         0.
##   1102.1138   283.71545  317.3093     0.         0.      1307.3981
##      7.85791  625.57605    0.         0.         0.       378.21414]]
print(test_y)
## [[1437  600  721  571  639    0    0 1293  440  528  455  446    0    0
##    997  417  486  418  431    0    0  837  430  434  353  437    0    0
##    996  423]]

4.8 Resultados obtenidos

Grafica de Datos de Predicción vs Datos Reales correspondientes a ese mismo periodo

plt.figure("Resultados")
plt.plot(test_y[0])
plt.plot(prediction_rescaled[0])
plt.legend(("Real", "Pred"))
plt.show()

plt.close()

Grafica de Datos de Predicción vs Datos Reales TOTALES, todo el archivo

plt.figure("Resultados General Costa Rica")
n_fechas = datos_pais_test.shape[1]
x_eje_r = list(range(0, n_fechas))
x_eje_p = list(range(n_fechas-dias_pronostico, n_fechas))
plt.plot(x_eje_r, datos_pais_test.loc[pais[0]])
plt.plot(x_eje_p, prediction_rescaled[0])
plt.legend(("Real", "Pred"))
plt.show()

plt.close()

Referencias

[1] Saffa, F. (2020). “Exploring the Link between COVID-19 and Depression using Neural Networks”. Recuperado de: https://towardsdatascience.com/exploring-the-link-between-covid-19-and-depression-using-neural-networks-469030112d3d

[2] COVID-19 Data Repository by the Center for Systems Science and Engineering (CSSE) at Johns Hopkins University. Recuperado de: https://github.com/CSSEGISandData/COVID-19

[3] Dong E, Du H, Gardner L. An interactive web-based dashboard to track COVID-19 in real time. Lancet Inf Dis. 20(5):533-534. doi: 10.1016/S1473-3099(20)30120-1

Referencia general sobre RNN vs LSTM(No usada en código): https://medium.com/microsoftazure/neural-networks-for-forecasting-financial-and-economic-time-series-6aca370ff412

TensorFlow Time series forecasting: https://www.tensorflow.org/tutorials/structured_data/time_series

Profe en clase: https://www.analyticsvidhya.com/blog/2018/02/time-series-forecasting-methods/